<?php
/*****************************************************

  Copyright:	(c) 2008  SeaDesign Web Studio
        Web:	www.seadesign.ru
      Email: 	seadesign@gmail.com
  
*****************************************************/

ini_set("memory_limit","64M");

/**
	ATTENTION!
	Never use IMG_XXX constants
	Use IMAGETYPE_XXX instead
	There is an error IMG_PNG = 4 however it must be (like IMAGETYPE_PNG) = 3 
*/
class Image
{
	/**
		whether to use ImageMagick command-line tools instead of GD library functions
		it may be needed due to the memory limits - memory_limit is too low and can't be enlarged
	*/
	static public $USE_IMAGEMAGICK = false;
	
	function __construct($h)
	{
		if ($h === false) {
			throw new Exception('Invalid image handler');
		}
		$this->h = $h;
	}
	
	function __destruct()
	{
		imagedestroy($this->h);
	}
	
	static function create($width, $height)
	{
		return new Image( imagecreatetruecolor($width, $height) );
	}
	
	public function handle()
	{
		return $this->h;
	}
	
	public function width()
	{
		return imagesx($this->h);
	}
	
	public function height()
	{
		return imagesy($this->h);
	}
	
	public function copyResized($newWidth, $newHeight)
	{
		$tmp = Image::create($newWidth, $newHeight);
		
		if (!imagecopyresized(
				$tmp, 
				$this->h, 
				0, 0, 0, 0, 
				$newWidth, 
				$newHeight, 
				$this->width(), 
				$this->height()) )
		{
			throw new Exception('imagecopyresized failed');
		}
		
		return new Image($tmp);
	}
	
	public function copyResampled($newWidth, $newHeight)
	{	
		$tmp = Image::create($newWidth, $newHeight);
		
		if (!imagecopyresampled(
				$tmp->h, 
				$this->h, 
				0, 0, 0, 0, 
				$newWidth, 
				$newHeight, 
				$this->width(), 
				$this->height()) )
		{
			throw new Exception('imagecopyresampled failed');
		}
		
		return $tmp;
	}
	
	/**
		@param  $hide  0-100 (100 - hide part of desct image completely)
	*/
	public function putWatermark(Image $wm, $hide=100, $x=0, $y=0)
	{
		imagecopymerge($this->handle(), $wm->handle(), $x,$y, 0,0, $wm->width(),$wm->height(), $hide);
	}
	
	public function putWatermarkInCenter(Image $wm, $hide=100)
	{
		$this->putWatermark($wm, $hide, ($this->width()-$wm->width())/2, ($this->height()-$wm->height())/2);
	}
	
	public function putWatermarkInTiles(Image $wm, $hide=100)
	{
		for ($y=0; $y<$this->height(); $y+=$wm->height())
		{
			for ($x=0; $x<$this->width(); $x+=$wm->width())
			{
				$this->putWatermark($wm, $hide, $x, $y);
			}
		}
	}
	
	const IMAGE_TYPES = 'jpg,gif,png,bmp';
	
	static public function isImageFile($fpath)
	{
		$pathParts = pathinfo($fpath);
		return in_array(strtolower($pathParts['extension']),explode(',',self::IMAGE_TYPES));
	}
	
	static public function loadFromFile($fname)
	{
		$fname = trim($fname);
		
		$info = pathinfo($fname);
		$ext = strtolower($info['extension']);
		
		$img = false;
			
		if ($ext == 'gif') 
		{
			if (!(imagetypes() & IMAGETYPE_GIF)) {
				throw new Exception('GIF is not supported');
			}
			$img = imagecreatefromgif($fname);
		}
		else if ($ext == 'jpg' || $ext == 'jpeg') 
		{
			if (!(imagetypes() & IMAGETYPE_JPEG)) {
				throw new Exception('JPG is not supported');
			}
			$img = imagecreatefromjpeg($fname);
		}
		else if ($ext == 'png') 
		{
			if (!(imagetypes() & IMAGETYPE_PNG)) {
				throw new Exception('PNG is not supported');
			}
			$img = imagecreatefrompng($fname);
		}

		if ($img === false) {
			throw new Exception("Image creation failed: invalid file name [$fname]");
		}
		
		return new Image($img);
	}
	
	public function saveToFile($fname)
	{
		$info = pathinfo($fname);
		$ext = strtolower($info['extension']);
		
		$type = IMAGETYPE_GIF;
		if (strcasecmp($ext,'jpg') || strcasecmp($ext,'jpeg')) {
			$type = IMAGETYPE_JPEG;
		}
		else if (strcasecmp($ext,'png'))
		{
			$type = IMAGETYPE_PNG;
		}
		
		return $this->output($type,$fname);
	}
	
	/**
		verify you don't add whitespaces before or after your <?php ?> tags
		in main file and all required files also
	*/
	public function output($type, $fname=null)
	{
		if ($type == IMAGETYPE_GIF) {
			return imagegif($this->h,$fname);
		}
		else if ($type == IMAGETYPE_JPEG) {
			return imagejpeg($this->h,$fname);
		}
		else if ($type == IMAGETYPE_PNG) {
			return imagepng($this->h,$fname);
		}
	}
	
	static public function getImageType($fname)
	{
		$params = getimagesize($fname);
		return $params[2];
	}
	
	static public function getImageExt($fname,$includeDot=false)
	{
		return image_type_to_extension(self::getImageType($fname),$includeDot);
	}
	
	static public function getImageMime($fname)
	{
		$params = getimagesize($fname);
		return $params['mime'];
	}

	private $h = false;
}




class Thumbnail
{
	function __construct($fname, $maxWidth, $maxHeight)
	{
		$fname = trim($fname);
		$this->origName = $fname;
		$this->maxWidth = $maxWidth;
		$this->maxHeight = $maxHeight;
		
		$this->dirName = $_SERVER['DOCUMENT_ROOT']."/thumbnails/${maxWidth}X${maxHeight}";
		
		if (!file_exists($this->dirName)) 
		{
			if (!mkdir($this->dirName, 0755, true)) 
			{
				throw new Exception('Can not create path '.$this->dirName);
			}
		}
		
		$this->path = $this->dirName.'/'.str_replace('/', '_', $fname);
		$this->url = "/thumbnails/${maxWidth}X${maxHeight}".'/'.str_replace('/', '_', $fname);

		if (!$this->exist()) {
			$this->create();
		}

		$info = getimagesize($this->path);
		$this->width = $info[0];
		$this->height = $info[1];
	}
	
	public function path() 
	{
		return $this->path;
	}

	public function url() 
	{
		return $this->url;
	}
	
	public function width() 
	{
		return $this->width;
	}
	
	public function height() 
	{
		return $this->height;
	}

	
	static public $rootPath = null;
	
	
	public function __toString()
	{
		return "$this->name [$this->width x $this->height]";
	}
	
	public function toArray()
	{
		return array(
			'url' => $this->url,
			'width' => $this->width,
			'height' => $this->height,
			'source' => $this->origName
		);
	}
	
	
	private function exist()
	{
		if (file_exists($this->path)) 
		{
			return filemtime($this->path) > filemtime($this->origName);
		}
		return false;
	}
	
	private function create()
	{
		$newWidth = $newHeight = 0;
		if (!$this->calculateThumbSize($newWidth, $newHeight))
		{
			copy($this->origName, $this->path);
			return;
		}

		if (Image::$USE_IMAGEMAGICK)
		{
			exec("convert {$this->origName} -resize {$newWidth}x{$newHeight} {$this->path}");
		}
		else
		{
			$img = Image::loadFromFile($this->origName);
			$thumb = $img->copyResampled($newWidth, $newHeight);
			$thumb->saveToFile($this->path);
		}
	}
	
	
	/** 
		keeping the correct aspect ratio to avoid distortion images in thumbnail
		@return true if size of original image is smaller than max size so thumbnail must be created, false otherwise
	*/
	private function calculateThumbSize(&$newWidth, &$newHeight)
	{
		$imgInfo = getimagesize($this->origName);
		$origWidth = $imgInfo[0];
		$origHeight = $imgInfo[1];
		
		if ($origWidth <= $this->maxWidth && $origHeight <= $this->maxHeight) 
		{
			return false;
		}
		
		$wRatio = $this->maxWidth / $origWidth;
		$hRatio = $this->maxHeight / $origHeight;
			
		if (($origHeight * $wRatio) < $this->maxHeight)
		{
			$newWidth = $this->maxWidth;
			$newHeight = floor($origHeight * $wRatio);
		}
		else
		{
			$newHeight = $this->maxHeight;
			$newWidth = floor($origWidth * $hRatio);
		}
		return true;
	}
	
	private $origName = null;
	private $maxWidth = 100;
	private $maxHeight = 100;
	private $dirName = null;
	private $path = null;
	private $url = null;
	private $width = 0;
	private $height = 0;
}

?>